package com.UnionPayCenter.wechat;

import com.UnionPayCenter.enums.ErrorCodeEnum;
import com.UnionPayCenter.exception.ApiException;
import com.UnionPayCenter.util.HttpIOUtil;
import com.UnionPayCenter.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.util.ClassUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.util.Collections;
import java.util.Formatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Slf4j
public class WXCardSignatureUtil {
    //  腾讯位置服务key
    private String key = "RM6BZ-DXIK3-KEU3G-Y7XA4-WT3LF-PVBKA";

    /**
     * 获取微信签名信息
     *
     * @param cardId 请求页面地址
     * @return 返回map：noncestr:随机字符串；timestamp：签名时间戳；appid;微信公众号Id;signature:签名串
     * @throws ClientProtocolException
     * @throws IOException
     * @throws CloneNotSupportedException
     */
    public static Map<String, Object> getSignature(String cardId, String code, String openid, String appid, String secret) throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();


//        String appid = ConstantInterface.WX_ID;
//        String secret = ConstantInterface.WX_SECRECT;
        String token = getToken(appid, secret);
        String jsapi_ticket = getTicket(token);
        String nonce_str = createNonceStr();
        String timestamp = createTimestamp();

        List<String> signatureElements = Lists.newArrayList(jsapi_ticket, timestamp, cardId, nonce_str);
        if (StringUtils.isNotBlank(code)) {
            signatureElements.add(code);
        }
        if (StringUtils.isNotBlank(openid)) {
            signatureElements.add(openid);
        }

        Collections.sort(signatureElements);
        StringBuilder sb = new StringBuilder();
        for (String element : signatureElements) {
            sb.append(element);
        }
        log.info("wx signature string: {}", sb.toString());

        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(sb.toString().getBytes("UTF-8"));
            map.put("signature", byteToHex(crypt.digest()));
        } catch (Exception e) {
            throw new ApiException(ErrorCodeEnum.WX_SIGNATURE.code(), e.getMessage());
        }
        map.put("jsapi_ticket", jsapi_ticket);
        map.put("noncestr", nonce_str);
        map.put("timestamp", timestamp);
        map.put("appid", appid);
        return map;
    }

    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    public static String createNonceStr() {
        return UUID.randomUUID().toString();
    }

    public static String createTimestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

    /**
     * @param appid  小程序应用id
     * @param secret 小程序应用密钥
     * @return 返回token
     * @throws IOException
     * @throws CloneNotSupportedException
     */
    public static String getXcxToken(String appid, String secret) throws IOException, CloneNotSupportedException {
        //token获取有次数限制，需做本地保留
        try {
            //首先判断本地有无记录，记录是否过期 7200s
            boolean isExpired = WeChatSystemContext.getInstance().isExpired(appid);
            if (isExpired) {
                return getAccessToken(appid, secret);
            } else {
                return getXcxCurrentToken(appid, secret);
            }
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * @Description: 获取小程序当前token
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/6/20
     */
    public static String getXcxCurrentToken(String appid, String secret) throws IOException, CloneNotSupportedException {
        String accessToken = WeChatSystemContext.getInstance().getAccessToken(appid);
        String url = "https://api.weixin.qq.com/wxa/getnearbypoilist?page=1&page_rows=1&access_token=" + accessToken;
        HttpGet httpGet = new HttpGet(url);
        // 生成一个Http客户端对象
        HttpClient httpClient = new DefaultHttpClient();
        // 下面使用Http客户端发送请求，并获取响应内容
        InputStream inputStream = null;
        // 发送请求并获得响应对象
        HttpResponse mHttpResponse = null;

        BufferedReader bufferedReader = null;
        String result = "";
        String line;
        try {
            mHttpResponse = httpClient.execute(httpGet);
            // 获得响应的消息实体
            HttpEntity mHttpEntity = mHttpResponse.getEntity();

            // 获取一个输入流
            inputStream = mHttpEntity.getContent();
            bufferedReader = new BufferedReader(
                    new InputStreamReader(inputStream));
            while ((line = bufferedReader.readLine()) != null) {
                result += line;
            }
            JSONObject json = JSONObject.parseObject(result);
            if (json.getInteger("errcode") != 0) {
                accessToken = getAccessToken(appid, secret);
            }

            return accessToken;
        } catch (IOException e) {
            throw new IOException("判断小程序token是否有效异常！");
        } finally {
            bufferedReader.close();
            inputStream.close();
            httpGet.clone();
        }
    }

    /**
     * @param appid  公众号应用id
     * @param secret 公众号应用密钥
     * @return 返回token
     * @throws IOException
     * @throws CloneNotSupportedException
     */
    public static String getToken(String appid, String secret) throws Exception {
        //token获取有次数限制，需做本地保留
        try {
            //首先判断本地有无记录，记录是否过期 7200s
            boolean isExpired = WeChatSystemContext.getInstance().isExpired(appid);
            if (isExpired) {
                return getAccessToken(appid, secret);
            } else {
                return getCurrentToken(appid, secret);
            }
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * @Description: 获取公众号当前token
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/6/20
     */
    public static String getCurrentToken(String appid, String secret) throws IOException, CloneNotSupportedException {
        String accessToken = WeChatSystemContext.getInstance().getAccessToken(appid);
        String url = "https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=" + accessToken;
        HttpGet httpGet = new HttpGet(url);
        // 生成一个Http客户端对象
        HttpClient httpClient = new DefaultHttpClient();
        // 下面使用Http客户端发送请求，并获取响应内容
        InputStream inputStream = null;
        // 发送请求并获得响应对象
        HttpResponse mHttpResponse = null;

        BufferedReader bufferedReader = null;
        String result = "";
        String line;
        try {
            mHttpResponse = httpClient.execute(httpGet);
            // 获得响应的消息实体
            HttpEntity mHttpEntity = mHttpResponse.getEntity();

            // 获取一个输入流
            inputStream = mHttpEntity.getContent();
            bufferedReader = new BufferedReader(
                    new InputStreamReader(inputStream));
            while ((line = bufferedReader.readLine()) != null) {
                result += line;
            }
            JSONObject json = JSONObject.parseObject(result);
            if (json.containsKey("errcode")) {
                accessToken = getAccessToken(appid, secret);
            }

            return accessToken;
        } catch (IOException e) {
            throw new IOException("判断token是否有效异常！");
        } finally {
            bufferedReader.close();
            inputStream.close();
            httpGet.clone();
        }
    }

    /**
     * @Description: 获取公众号/小程序token
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/6/20
     */
    public static String getAccessToken(String appid, String secret) throws IOException, CloneNotSupportedException {
        try {
            String authAccessToken = ComponentUtil.getAuthAccessToken(appid);
            return authAccessToken;
        } catch (Exception e) {
            log.error("获取第三方token失败", e);
        }
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
//        log.info("get token url: {}", url);
        // 生成一个请求对象
        HttpGet httpGet = new HttpGet(url);
        // 生成一个Http客户端对象
        HttpClient httpClient = new DefaultHttpClient();
        // 下面使用Http客户端发送请求，并获取响应内容
        InputStream inputStream = null;
        // 发送请求并获得响应对象
        HttpResponse mHttpResponse = null;

        BufferedReader bufferedReader = null;
        String result = "";
        String line;
        try {
            mHttpResponse = httpClient.execute(httpGet);
            // 获得响应的消息实体
            HttpEntity mHttpEntity = mHttpResponse.getEntity();

            // 获取一个输入流
            inputStream = mHttpEntity.getContent();
            bufferedReader = new BufferedReader(
                    new InputStreamReader(inputStream));
            while ((line = bufferedReader.readLine()) != null) {
                result += line;
            }
            JSONObject json = JSONObject.parseObject(result);
            log.info(String.format("getAccessToken appId: %s, return data: %s", appid, json.toString()));
            if (json.containsKey("errcode")) {
                if(json.getInteger("errcode") == 40125){
                    throw new ApiException(ErrorCodeEnum.WX_SIGNATURE.code(), "小程序appid或appsecret不正确");
                }
                throw new ApiException(ErrorCodeEnum.WX_SIGNATURE.code(), json.getString("errmsg"));
            }
            String accessToken = json.get("access_token").toString();
            log.info(String.format("getAccessToken appId: %s, token: %s", appid, accessToken));

            //记录到配置 access_token 当前时间
            WeChatSystemContext.getInstance().saveLocalAccessonToke(appid, accessToken);

            return accessToken;
        } catch (IOException e) {
            throw new IOException("获取access_token异常！");
        } finally {
            bufferedReader.close();
            inputStream.close();
            httpGet.clone();
        }
    }

    /**
     * @param access_token 生成的token
     * @return 返回jsapi_ticket
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static String getTicket(String access_token) throws ClientProtocolException, IOException {
        HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=wx_card");
        // 生成一个Http客户端对象
        HttpClient httpClient = new DefaultHttpClient();
        // 下面使用Http客户端发送请求，并获取响应内容
        InputStream inputStream = null;
        // 发送请求并获得响应对象
        HttpResponse mHttpResponse = null;

        BufferedReader bufferedReader = null;
        String result = "";
        String line;
        try {
            mHttpResponse = httpClient.execute(httpGet);
            HttpEntity mHttpEntity = mHttpResponse.getEntity();
            inputStream = mHttpEntity.getContent();
            bufferedReader = new BufferedReader(
                    new InputStreamReader(inputStream));
            while ((line = bufferedReader.readLine()) != null) {
                result += line;
            }
            JSONObject json2 = JSONObject.parseObject(result);
            log.info(String.format("getTicket return data: %s", json2.toString()));

            return json2.get("ticket").toString();
        } catch (IOException e) {
            throw new IOException("获取jsapi_ticket异常！");
        } finally {
            bufferedReader.close();
            inputStream.close();
        }
    }

    /**
     * code解密获取真实卡号
     *
     * @param code
     * @return
     * @throws Exception
     */
    public static String descryptCode(String appid, String appsecret, String code) throws Exception {
        String token = getToken(appid, appsecret);
        String urlStr = "https://api.weixin.qq.com/card/code/decrypt?access_token=" + token;

        JSONObject params = new JSONObject();
        params.put("encrypt_code", code);
        String result = "";
        try {
            //建立http连接
            URL url = new URL(urlStr);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setRequestMethod("POST");
            urlConnection.setUseCaches(false);
            urlConnection.setRequestProperty("Content-Type", "application/json");
            urlConnection.connect();
            //发送数据
            DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
            out.writeBytes(params.toJSONString());
            out.flush();
            out.close();
            //读取数据
            BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String line;
            StringBuffer buffer = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            result = buffer.toString();
            urlConnection.disconnect();
            reader.close();

            //返回卡号
            JSONObject reJson = JSONObject.parseObject(result);
            log.info(String.format("descryptCode appid: %s, code: %s, return data: %s", appid, code, reJson.toString()));
            return reJson.getString("code");
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * @Description: 发送公众号模版消息
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/6/20
     */
    public static boolean templateSend(String appid, String appsecret, String params) throws Exception {
        String token = getToken(appid, appsecret);
        String urlStr = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + token;

        String result = "";
        try {
            //建立http连接
            URL url = new URL(urlStr);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setRequestMethod("POST");
            urlConnection.setUseCaches(false);
            urlConnection.setRequestProperty("Content-Type", "application/json");
            urlConnection.connect();
            //发送数据
            DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
            out.write(params.getBytes("utf-8"));
            out.flush();
            out.close();
            //读取数据
            BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String line;
            StringBuffer buffer = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            result = buffer.toString();
            urlConnection.disconnect();
            reader.close();

            JSONObject reJson = JSONObject.parseObject(result);
            log.info(String.format("templateSend appid: %s, return data: %s", appid, reJson.toString()));
            if (0 == reJson.getInteger("errcode")) {
                return true;
            }
            return false;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * @Description: 支付成功获取unionid
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/6/17
     */
    public static String getPaidUnionId(String appid, String appsecret, String transaction_id, String openid) throws Exception {
        String token = getXcxToken(appid, appsecret);
        String urlStr = "https://api.weixin.qq.com/wxa/getpaidunionid?access_token=" + token + "&transaction_id=" + transaction_id +
                "&openid=" + openid;

        HttpGet httpGet = new HttpGet(urlStr);
        // 生成一个Http客户端对象
        HttpClient httpClient = new DefaultHttpClient();
        // 下面使用Http客户端发送请求，并获取响应内容
        InputStream inputStream = null;
        // 发送请求并获得响应对象
        HttpResponse mHttpResponse = null;

        BufferedReader bufferedReader = null;
        String result = "";
        String line;
        try {
            mHttpResponse = httpClient.execute(httpGet);
            HttpEntity mHttpEntity = mHttpResponse.getEntity();
            inputStream = mHttpEntity.getContent();
            bufferedReader = new BufferedReader(
                    new InputStreamReader(inputStream));
            while ((line = bufferedReader.readLine()) != null) {
                result += line;
            }
            JSONObject json = JSONObject.parseObject(result);
            log.info(String.format("getPaidUnionId appid: %s, openid: %s, return data: %s", appid, openid, json.toString()));
            if (json.getInteger("errcode") == 0) {
                return json.getString("unionid");
            }
            return null;
        } catch (Exception e) {
            throw new IOException("支付成功获取unionid异常！");
        } finally {
            bufferedReader.close();
            inputStream.close();
        }
    }

    /**
     * @Description: 发送小程序模版消息
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/6/20
     */
    public static boolean xcxTemplateSend(String appid, String appsecret, String params) throws Exception {
        String token = getXcxToken(appid, appsecret);
        String urlStr = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=" + token;

        String result = "";
        try {
            //建立http连接
            URL url = new URL(urlStr);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setRequestMethod("POST");
            urlConnection.setUseCaches(false);
            urlConnection.setRequestProperty("Content-Type", "application/json");
            urlConnection.connect();
            //发送数据
            DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
            out.write(params.getBytes("utf-8"));
            out.flush();
            out.close();
            //读取数据
            BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String line;
            StringBuffer buffer = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            result = buffer.toString();
            urlConnection.disconnect();
            reader.close();

            JSONObject reJson = JSONObject.parseObject(result);
            log.info(String.format("xcxTemplateSend, parmas: %s, appid: %s, return data: %s", params, appid, reJson.toString()));
            if (0 == reJson.getInteger("errcode")) {
                return true;
            }
            return false;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * @Description: 微信公众号上传素材/图片
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/7/8
     */
    public static String uploadImg(String appid, String appsecret, MultipartFile file) throws Exception {
        String token = getToken(appid, appsecret);
        String urlStr = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=" + token;

        HttpIOUtil httpClient = new HttpIOUtil();

        File toFile = null;
        if (file.equals("") || file.getSize() <= 0) {
            return null;
        } else {
            InputStream ins = file.getInputStream();
            toFile = new File(file.getOriginalFilename());
            httpClient.inputStreamToFile(ins, toFile);
            ins.close();
        }

        Map<String, File> fileMap = new HashMap<String, File>();
        fileMap.put("buffer", toFile);
        String ret = httpClient.formUpload(urlStr, null, fileMap);
        JSONObject reJson = JSONObject.parseObject(ret);
        if (reJson.containsKey("url")) {
            log.info(String.format("微信上传素材成功，appid: %s, url：%s", appid, reJson.getString("url")));
            return reJson.getString("url");
        }
        log.error(String.format("微信上传素材失败，appid: %s", appid));
        throw new IOException("微信上传素材失败！");
    }

    /**
     * @Description: 创建会员卡
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/7/10
     */
    public static String createCard(String appid, String appsecret, String params) throws Exception {
        String token = getToken(appid, appsecret);
        String urlStr = "https://api.weixin.qq.com/card/create?access_token=" + token;

        String result = "";
        try {
            //建立http连接
            URL url = new URL(urlStr);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setRequestMethod("POST");
            urlConnection.setUseCaches(false);
            urlConnection.setRequestProperty("Content-Type", "application/json");
            urlConnection.connect();
            //发送数据
            DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
            out.write(params.getBytes("utf-8"));
            out.flush();
            out.close();
            //读取数据
            BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String line;
            StringBuffer buffer = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            result = buffer.toString();
            urlConnection.disconnect();
            reader.close();

            JSONObject reJson = JSONObject.parseObject(result);
            log.info(String.format("createCard appid: %s, return data: %s", appid, reJson.toString()));
            if (0 == reJson.getInteger("errcode")) {
                return reJson.getString("card_id");
            }
            return null;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * @Description: 修改会员卡
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/7/10
     */
    public static boolean updateCard(String appid, String appsecret, String params) throws Exception {
        String token = getToken(appid, appsecret);
        String urlStr = "https://api.weixin.qq.com/card/update?access_token=" + token;

        String result = "";
        try {
            //建立http连接
            URL url = new URL(urlStr);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setRequestMethod("POST");
            urlConnection.setUseCaches(false);
            urlConnection.setRequestProperty("Content-Type", "application/json");
            urlConnection.connect();
            //发送数据
            DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
            out.write(params.getBytes("utf-8"));
            out.flush();
            out.close();
            //读取数据
            BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String line;
            StringBuffer buffer = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            result = buffer.toString();
            urlConnection.disconnect();
            reader.close();

            JSONObject reJson = JSONObject.parseObject(result);
            log.info(String.format("updateCard appid: %s, return data: %s", appid, reJson.toString()));
            if (0 == reJson.getInteger("errcode")) {
                return true;
            }
            return false;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * @Description: 设置开卡信息选项
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/7/10
     */
    public static boolean setCard(String appid, String appsecret, String params) throws Exception {
        String token = getToken(appid, appsecret);
        String urlStr = "https://api.weixin.qq.com/card/membercard/activateuserform/set?access_token=" + token;

        String result = "";
        try {
            //建立http连接
            URL url = new URL(urlStr);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setRequestMethod("POST");
            urlConnection.setUseCaches(false);
            urlConnection.setRequestProperty("Content-Type", "application/json");
            urlConnection.connect();
            //发送数据
            DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
            out.write(params.getBytes("utf-8"));
            out.flush();
            out.close();
            //读取数据
            BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String line;
            StringBuffer buffer = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            result = buffer.toString();
            urlConnection.disconnect();
            reader.close();

            JSONObject reJson = JSONObject.parseObject(result);
            log.info(String.format("setCard appid: %s, return data: %s", appid, reJson.toString()));
            if (0 == reJson.getInteger("errcode")) {
                return true;
            }
            return false;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * @Description: 获取用户开卡信息
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/7/10
     */
    public static JSONObject getUserinfoByCard(String appid, String appsecret, String params) throws Exception {
        String token = getToken(appid, appsecret);
        String urlStr = "https://api.weixin.qq.com/card/membercard/userinfo/get?access_token=" + token;

        String result = "";
        try {
            //建立http连接
            URL url = new URL(urlStr);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setRequestMethod("POST");
            urlConnection.setUseCaches(false);
            urlConnection.setRequestProperty("Content-Type", "application/json");
            urlConnection.connect();
            //发送数据
            DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
            out.write(params.getBytes("utf-8"));
            out.flush();
            out.close();
            //读取数据
            BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String line;
            StringBuffer buffer = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            result = buffer.toString();
            urlConnection.disconnect();
            reader.close();

            JSONObject reJson = JSONObject.parseObject(result);
            log.info(String.format("getUserinfoByCard appid: %s, return data: %s", appid, reJson.toString()));
            if (0 == reJson.getInteger("errcode")) {
                return reJson;
            }
            return null;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * @Description: 开卡组件
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/7/10
     */
    public static JSONObject activateCard(String appid, String appsecret, String params) throws Exception {
        String token = getToken(appid, appsecret);
        String urlStr = "https://api.weixin.qq.com/card/membercard/activate/geturl?access_token=" + token;

        String result = "";
        try {
            //建立http连接
            URL url = new URL(urlStr);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setRequestMethod("POST");
            urlConnection.setUseCaches(false);
            urlConnection.setRequestProperty("Content-Type", "application/json");
            urlConnection.connect();
            //发送数据
            DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
            out.write(params.getBytes("utf-8"));
            out.flush();
            out.close();
            //读取数据
            BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String line;
            StringBuffer buffer = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            result = buffer.toString();
            urlConnection.disconnect();
            reader.close();

            JSONObject reJson = JSONObject.parseObject(result);
            log.info(String.format("activateCard appid: %s, return data: %s", appid, reJson.toString()));
            if (0 == reJson.getInteger("errcode")) {
                JSONObject json = new JSONObject();
                String reUrl = URLDecoder.decode(reJson.getString("url"), "UTF-8");
                String u1[] = reUrl.split("&encrypt_card_id=");
                String u2[] = u1[1].split("&outer_str=");
                String u3[] = u2[1].split("&biz=");
                String u4[] = u3[1].split("#wechat_redirect");
                json.put("encrypt_card_id", u2[0]);
                json.put("outer_str", u3[0]);
                json.put("biz", u4[0]);
                return json;
            }
            return null;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * @Description: 获取小程序码
     * @Param:
     * @return:
     * @Author: bite
     * @Date: 2019/7/10
     */
    public static boolean getUnlimited(String appid, String appsecret, String params, String path) throws Exception {
        String token = getXcxToken(appid, appsecret);
        String urlStr = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + token;

        try {
            //建立http连接
            HttpClientBuilder httpClientBuilder = HttpClients.custom();
            CloseableHttpClient httpClient = httpClientBuilder.build();
            HttpRequestBase httpBase = createHttpBase(urlStr, params, true);
            CloseableHttpResponse response = httpClient.execute(httpBase);
            HttpEntity httpEntity = response.getEntity();
            byte[] bytes = EntityUtils.toByteArray(response.getEntity());
            if (httpEntity.getContentType().getValue().contains(ContentType.APPLICATION_JSON.getMimeType())) {
                String responseData = new String(bytes);
                log.info("get qr code error: {}, {}", urlStr, responseData);
                throw new ApiException(ErrorCodeEnum.WD11001.code(), responseData);
            }
            //String path = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "static" + name;
            Files.write(Paths.get(path), bytes);
            //URL url = new URL(urlStr);
            //HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            //urlConnection.setDoOutput(true);
            //urlConnection.setDoInput(true);
            //urlConnection.setRequestMethod("POST");
            //urlConnection.setUseCaches(false);
            //urlConnection.setRequestProperty("Content-Type", "application/json");
            //urlConnection.connect();
            ////发送数据
            //DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
            //out.write(params.getBytes("utf-8"));
            //out.flush();
            //out.close();


            //InputStream inputStream = urlConnection.getInputStream();

            //if (inputStream != null) {
            //    try {
            //        String path = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "static" + name;
            //        File file = new File(path);
            //        FileOutputStream fos = new FileOutputStream(file);
            //        byte[] b = new byte[1024];
            //        int nRead = 0;
            //        while ((nRead = inputStream.read(b)) != -1) {
            //            fos.write(b, 0, nRead);
            //        }
            //        fos.flush();
            //        fos.close();

            //        log.info(String.format("getUnlimited params：%s success", params));
            //        return true;
            //    } catch (Exception e) {
            //        e.printStackTrace();
            //    }
            //}

            return true;
        } catch (Exception e) {
            throw e;
        }
    }

    private static HttpRequestBase createHttpBase(String url, String requestStr, boolean isPost) {
        HttpRequestBase httpBase;
        if (isPost) {
            httpBase = new HttpPost(url);
            ((HttpPost) httpBase).setEntity(createEntry(requestStr));
        } else {
            httpBase = new HttpGet(url);
        }

        httpBase.setConfig(RequestConfig.custom()
                .setConnectionRequestTimeout(10000)
                .setConnectTimeout(10000)
                .setSocketTimeout(10000)
                .build());

        return httpBase;
    }

    private static StringEntity createEntry(String requestStr) {
        try {
            return new StringEntity(new String(requestStr.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
        } catch (UnsupportedEncodingException e) {
            //cannot happen
            log.error(e.getMessage(), e);
            return null;
        }
    }

}
